function VigenèreAutokeyCipher(key, abc, l = abc.length) {
    this.fillOthers = function (str, code) {
        var result = ''
        for (var i = 0, k = 0; i < str.length; i++) {
            if (abc.includes(str[i])) result += code[k++];
            else result += str[i];
        }
        return result;
    }

    this.encode = function (str) {
        var s = str.replace(new RegExp(`[^${abc}]`, 'g'), '');
        var full_key = key.padEnd(s.length, s);
        var code = [...s].map((v, i) => abc.includes(v) ? abc[(abc.indexOf(v) + abc.indexOf(full_key[i])) % l] : v).join('')
        return this.fillOthers(str, code)
    };
    this.decode = function (str) {
        var s = str.replace(new RegExp(`[^${abc}]`, 'g'), '');
        var key_part = [...s.substr(0, key.length)].map((v, i) => abc.includes(v) ? abc[(abc.indexOf(v) - abc.indexOf(key[i]) + l) % l] : v).join('')
        s = s.slice(key.length);
        var rest_part = ''
        var sub_key = key_part;
        while (s.length) {
            var rest = s.slice(0, key.length);
            var rest_key = sub_key.substr(0, rest.length);
            sub_key = [...rest.substr(0, key.length)].map((v, i) => abc.includes(v) ? abc[(abc.indexOf(v) - abc.indexOf(sub_key[i]) + l) % l] : v).join('')
            rest_part += sub_key;
            s = s.slice(key.length);
        }
        var code = key_part + rest_part;
        return this.fillOthers(str, code)
    };
}
